from typing import List,Dict
from dataclasses import dataclass
from requests_async import post,get
import time
from datetime import datetime
import asyncio,json
from .models import Submission
HEARTBEAT_TIMEOUT=5
class Judger:
    name:str=None
    ip_addr:str="255.255.255.255"
    capa:List[str]=[]
    last_heartbeat:int=0
    on_going:List[int]=[]
    def has_capa(self,cap):
        return self.capa.count(cap)>0
    def is_online(self):
        return False if time.monotonic()-self.last_heartbeat>HEARTBEAT_TIMEOUT else True
    def update(self):
        self.last_heartbeat=time.monotonic()
    async def force_check(self):
        response=await get(f"http://{self.ip_addr}/check/",timeout=HEARTBEAT_TIMEOUT)
        return response.status_code==200
    def avaliable(self,cap):
        return self.has_capa(cap) and self.is_online()
    async def submit(self,rid:int):
        sub=await Submission.objects.aget(id=rid)
        print(self.name," submit ",rid)
        response=await post(f"http://{self.ip_addr}/submit/",json=sub.to_json())
        if response.status_code==200:
            self.on_going.append(rid)
        return response.status_code
    def complete(self,rid:int):
        self.on_going.remove(rid)
judgers:Dict[str,Judger]={}

def get_judger(typ):
    global judgers
    can:List[Judger]=[]
    for i in judgers:
        j=judgers[i]
        if j.avaliable(typ):
            can.append(j)
    if len(can)==0:
        raise RuntimeWarning(f"[Warn {datetime.now()}] no avaliable judger for {typ}")
        return None
    return min(can,key=lambda x:len(x.on_going))

async def register(name,ip,cap)->Judger:
    if name in judgers:
        judgers[name].ip_addr=ip
        judgers[name].capa=cap
        judgers[name].last_heartbeat=time.monotonic()
        return judgers[name]
    j=Judger()
    j.capa=cap
    j.ip_addr=ip
    j.name=name
    j.last_heartbeat=time.monotonic()
    judgers[name]=j
    return judgers[name]
